import Container from "../container";
import Injection from "../injection";
import MetaHandle from "../meta-handle";

//容器操作类
export default class instanceHandle {
  //可初始化的容器
  static serviceMap = new Map<Object, instanceHandle>();

  //标记此容器为可初始化
  static Init(instance: Object, prototype: Object) {
    let instanceHandle = this.factory(instance, prototype, true);
    instanceHandle.bindInjection(prototype);
    return instanceHandle;
  }

  static factory(
    instance: Object,
    prototype?: Object
  ): instanceHandle | undefined;
  static factory(
    instance: Object,
    prototype: Object,
    create: true
  ): instanceHandle;
  static factory(instance: Object, prototype: Object, create: boolean = false) {
    if (!this.serviceMap.has(instance)) {
      if (create) {
        this.serviceMap.set(instance, new this(instance, prototype));
      }
    }
    return this.serviceMap.get(instance);
  }

  constructor(private instance: Object, private prototype: Object) {
    setTimeout(() => {
      if (!this.isInit) throw new Error("容器未初始化");
    });
  }

  private _haveDestroy: boolean = false;

  get haveDestroy(): boolean {
    return this._haveDestroy;
  }

  set haveDestroy(newVal: boolean) {
    this._haveDestroy = newVal;
  }

  //绑定注入类
  private injectionSet!: Set<Injection>;
  bindInjection(prototype: Object) {
    this.injectionSet = MetaHandle.getInjection(
      prototype.constructor as Constructor
    );
    MetaHandle.deleteInjection(prototype.constructor as Constructor);
  }

  //绑定初始化后执行的回调
  private alreadySet: Set<Function> = new Set();
  alreadyFn(cb: Function) {
    if (this.isInit) {
      cb();
    } else {
      this.alreadySet.add(cb);
    }
  }

  //用于单例模式下的容器工具实例
  container!: Container | null;
  bindContainer(container: Container) {
    !this.container && (this.container = container);
    return this;
  }
  private isInit: boolean = false;
  //初始化容器
  init() {
    let serviceList: Array<instanceHandle> = [
      ...instanceHandle.serviceMap.values(),
    ];

    serviceList.forEach((instanction) => {
      if (!instanction.isInit) {
        //遍历注入类

        instanction.injectionSet.forEach((injection) => {
          let token = injection.getToken();
          let factory = injection.factory() as Object;
          if (token) {
            //如果是单例模式（即共享注入）
            if (instanction.container) {
              instanction.container.setData(token, factory);

              Reflect.set(
                instanction.prototype,
                injection.key,
                instanction.container.getData(token)
              );
            } else {
              //非单例模式（创建新注入类实例 进行注入操作）
              Reflect.set(instanction.prototype, injection.key, factory);
            }
          }

          instanction.isInit = true;

          if ((factory.constructor as any).isService) {
            instanceHandle.serviceMap.get(factory)?.init();
          }
        });
        instanction.alreadySet.forEach((fn) => {
          fn();
        });
        instanction.alreadySet.clear();
      }
    });
  }

  //销毁
  destroy() {
    this.injectionSet.forEach((injection) => {
      Reflect.deleteProperty(this.prototype, injection.key);
    });
    this.injectionSet.clear();
    this.haveDestroy = true;

    if (this.container) {
      this.container.destroy();
      this.container = null;
    }
    instanceHandle.serviceMap.delete(this.instance);
  }
}
